package org.zhc.service.impl;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.zhc.context.ActionContext;
import org.zhc.po.Action;
import org.zhc.po.Property;
import org.zhc.po.Result;
import org.zhc.service.LoadConfigService;

public class LoadAnnotationConfig implements LoadConfigService {

	private static final Logger logger = Logger
			.getLogger(LoadAnnotationConfig.class.getName());
	private Set<String> classes = new HashSet<String>();// 应用下所有类的类名
	private Set<Class<?>> actionClasses = new HashSet<Class<?>>();// 所有被注解为ActionClass的类的class对象

	@Override
	public void loadAcionConfig(InputStream xmlInputStream) {
		this.findClasss(ActionContext.getApplicationFilePath() + "WEB-INF"
				+ System.getProperty("file.separator") + "classes");
		this.findActionClasses();
		this.loadActions();
	}

	/**
	 * 递归查询一个目录下的所有.class文件
	 * 
	 * @param path
	 *            目录路径
	 */
	private void findClasss(String path) {
		File file = new File(path);
		if (file.exists()) {
			File[] children = file.listFiles();
			if (children != null) {
				for (File child : children) {
					if (child.isFile()) {
						if (child.getName().substring(
								child.getName().lastIndexOf(".")).equals(
								".class")) {
							String classPath = child
									.getPath()
									.substring(
											(ActionContext
													.getApplicationFilePath()
													+ "WEB-INF"
													+ System
															.getProperty("file.separator")
													+ "classes" + System
													.getProperty("file.separator"))
													.length())
									.replace(
											System
													.getProperty("file.separator"),
											".");
							classPath = classPath.substring(0, (classPath
									.length() - ".class".length()));
							classes.add(classPath);
						}
					} else if (child.isDirectory()) {// 递归
						if (file.getPath().contains("classes"))
							findClasss(child.getPath());
					}
				}
			}
		}
	}

	/**
	 * 从已经获得所有的类中查询为action的类
	 */
	private void findActionClasses() {
		try {
			for (String classPath : classes) {
				Class<?> _class = Class.forName(classPath);
				if (_class
						.isAnnotationPresent(org.zhc.annotation.ActionClass.class)) {
					actionClasses.add(_class);
				}
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
	}

	private void loadActions() {
		for (Class<?> _class : actionClasses) {
			findActionMethods(_class);
		}
	}

	/**
	 * 查询一个类中所有被配置成action的方法
	 * 
	 * @param _class
	 *            类的class对象
	 * @return
	 */
	private Set<String> findActionMethods(Class<?> _class) {
		Set<String> meths = new HashSet<String>();
		Method[] methods = _class.getMethods();
		if (methods != null) {
			for (Method mth : methods) {
				if (mth.isAnnotationPresent(org.zhc.annotation.Action.class)) {
					meths.add(mth.getName());
					org.zhc.annotation.Action actionAnn = mth
							.getAnnotation(org.zhc.annotation.Action.class);
					Map<String, Action> actions = ActionContext
							.getAction(actionAnn.namespace());
					if (actions != null && actions.size() > 0) {// 如果用户已经在XML中配置了该namespace
						if (actions.get(actionAnn.name()) == null) {// 如果用户没有配置相同名称的action，则添加，否则不作处理
							loadParams(actionAnn);//
							loadAttributes(actionAnn);
							loadResults(mth);
							actions.put(actionAnn.name(), new Action(actionAnn
									.name(), _class.getName(), mth.getName(),
									loadResults(mth), loadParams(actionAnn),
									loadAttributes(actionAnn)));
						}
					} else {// 如果用户还没有定义该namespace，则必须创建
						Map<String, Action> _actions = new HashMap<String, Action>();
						_actions.put(actionAnn.name(), new Action(actionAnn
								.name(), _class.getName(), mth.getName(),
								loadResults(mth), loadParams(actionAnn),
								loadAttributes(actionAnn)));
						ActionContext.addNamespace(actionAnn.namespace(),
								_actions);
					}
				}
			}
		}
		return meths;
	}

	/**
	 * 获得一个action所有的param
	 * 
	 * @param action
	 *            action的注解对象
	 * @return
	 */
	private Set<String> loadParams(org.zhc.annotation.Action action) {
		Set<String> params = new HashSet<String>();
		String[] fields = action.param();
		if (fields != null) {
			for (String field : fields) {
				params.add(field);
			}
		}
		return params;
	}

	/**
	 * 获得一个action所有的attribute
	 * 
	 * @param action
	 *            action的注解对象
	 * @return
	 */
	private Set<String> loadAttributes(org.zhc.annotation.Action action) {
		Set<String> attrs = new HashSet<String>();
		String[] fields = action.attribute();
		if (fields != null) {
			for (String field : fields) {
				attrs.add(field);
			}
		}
		return attrs;
	}

	/**
	 * 获得一个action下面所有的result注解
	 * 
	 * @param method
	 *            方法的method对象
	 * @return
	 */
	private List<Result> loadResults(Method method) {
		List<Result> results = new ArrayList<Result>();
		org.zhc.annotation.Results aResults = method
				.getAnnotation(org.zhc.annotation.Results.class);
		if (aResults != null) {// 查找param的注解
			org.zhc.annotation.Result[] _results = aResults.value();
			if (_results != null) {
				for (org.zhc.annotation.Result result : _results) {
					results.add(new Result(result.value(), result.type()
							.getStringType(), result.location(),
							loadResultProperties(result),
							loadResultAttributes(result)));
				}
			}
		}
		return results;
	}

	/**
	 * 获得result下面所有的property
	 * 
	 * @param result
	 *            一个action中结果中的Result的注解对象
	 * @return
	 */
	private List<Property> loadResultProperties(org.zhc.annotation.Result result) {
		List<Property> properties = new ArrayList<Property>();
		org.zhc.annotation.Property[] aProperties = result.property();
		if (aProperties != null) {
			for (org.zhc.annotation.Property property : aProperties) {
				properties.add(new Property(property.name(), property.value()));
			}
		}
		return properties;
	}

	/**
	 * 获得result下面所有的attribute
	 * 
	 * @param result
	 *            一个action中结果中的Result的注解对象
	 * @return
	 */
	private Set<String> loadResultAttributes(org.zhc.annotation.Result result) {
		Set<String> attributes = new HashSet<String>();
		String[] attrs = result.attribute();
		if (attrs != null) {
			for (String attribute : attrs) {
				attributes.add(attribute);
			}
		}
		return attributes;
	}
}
